package com.dss.auto_deploy.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dss.auto_deploy.config.DssProperties;
import com.dss.auto_deploy.config.WebsocketEndPoint;
import com.dss.auto_deploy.domain.AdmNamespace;
import com.dss.auto_deploy.domain.AdmProject;
import com.dss.auto_deploy.domain.Deploy;
import com.dss.auto_deploy.domain.Server;
import com.dss.auto_deploy.dto.SelectDto;
import com.dss.auto_deploy.dto.WsSendDto;
import com.dss.auto_deploy.enums.BooleanTypeEnum;
import com.dss.auto_deploy.enums.LastStatusEnum;
import com.dss.auto_deploy.event.UploadAndStartEvent;
import com.dss.auto_deploy.mapper.AdmNamespaceMapper;
import com.dss.auto_deploy.mapper.AdmProjectMapper;
import com.dss.auto_deploy.mapper.IDeployMapper;
import com.dss.auto_deploy.service.IDeployService;
import com.dss.auto_deploy.service.IServerService;
import com.dss.auto_deploy.util.*;
import com.dss.auto_deploy.vo.DeployVo;
import com.jcraft.jsch.Session;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;

/**
 * @author: dongshoushan
 * @date: 2021年01月18日 16:44
 */
@Service
@Slf4j
@RequiredArgsConstructor(onConstructor = @_(@Autowired))
public class DeployServiceImpl extends ServiceImpl<IDeployMapper, Deploy> implements IDeployService {
    private final IDeployMapper deployMapper;
    private final ThreadPoolTaskExecutor threadPoolTaskExecutor;
    private final RemoteSshUtil remoteSshUtil;
    private final DssProperties dssProperties;
    private final ApplicationEventPublisher publisher;
    private final WebsocketEndPoint websocketEndPoint;
    private final AdmProjectMapper admProjectMapper;
    @Lazy
    private final IServerService serverService;
    private final AdmNamespaceMapper admNamespaceMapper;

    @Override
    public void insertDeploy(Deploy deploy) {
        deploy.setLastStatus(LastStatusEnum.INIT.getCode());
        deployMapper.insert(deploy);
    }

    @Override
    public void updateDeploy(Deploy deploy) {
        deployMapper.updateById(deploy);
    }

    @Override
    public void deleteDeploy(Long id) {
        deployMapper.deleteById(id);
    }

    @Override
    public Page<DeployVo> getList(SelectDto pageReq) {
        Page<Deploy> tablesPage = new Page<>(pageReq.getPage(), pageReq.getLimit());
        LambdaQueryWrapper<Deploy> wrapper = Wrappers.lambdaQuery(Deploy.class)
                .like(StringUtils.isNotEmpty(pageReq.getContent()), Deploy::getModuleName, pageReq.getContent())
                .eq(pageReq.getNamespaceId() != null, Deploy::getNamespaceId, pageReq.getNamespaceId())
                .eq(pageReq.getProjectId() != null, Deploy::getProjectId, pageReq.getProjectId())
                .eq(pageReq.getServerId() != null, Deploy::getServerId, pageReq.getServerId())
                .eq(pageReq.getType() != null, Deploy::getType, pageReq.getType())
                .orderByDesc(Deploy::getLastDeployDate)
                ;
        Page<Deploy> pageSelectResult = deployMapper.selectPage(tablesPage, wrapper);
        List<Deploy> records = pageSelectResult.getRecords();
        List<DeployVo> voList = convertToVo(records);
        Page<DeployVo> page = new Page<>();
        page.setRecords(voList);
        page.setTotal(pageSelectResult.getTotal());
        page.setSize(pageSelectResult.getSize());
        return page;
    }

    @Override
    public List<DeployVo> convertToVo(List<Deploy> records) {
        if (CollectionUtil.isEmpty(records)){
            return new ArrayList<>();
        }
        List<DeployVo> deployVos = BeanUtils.copyList(records, DeployVo.class);
        List<Server> serverList = serverService.getAll();
        List<AdmProject> projectList = SpringUtils.getBean(AdmProjectServiceImpl.class).getAll();
        List<AdmNamespace> namespaceList = SpringUtils.getBean(AdmNamespaceServiceImpl.class).getAll();
        deployVos.forEach(vo -> {
            Server server = serverList.stream().filter(s -> s.getId().equals(vo.getServerId())).findFirst().orElse(null);
            vo.setIp(server.getIp());
            vo.setPassword(server.getPassword());
            vo.setUsername(server.getUsername());
            vo.setPort(server.getPort());
            vo.setVpn(server.getVpn());
            vo.setProjectName(Objects.requireNonNull(projectList.stream().filter(s -> s.getId().equals(vo.getProjectId())).findFirst().orElse(null)).getProjectName());
            vo.setNamespaceName(Objects.requireNonNull(namespaceList.stream().filter(s -> s.getId().equals(vo.getNamespaceId())).findFirst().orElse(null)).getName());
            vo.setServerName(server.getName());
        });
        return deployVos;
    }

    /**
     * 编译构建,构建成功的直接丢事件进行部署
     *
     * @param mavens 编译命令
     * @param list   需要构建的
     * @param split  所有要部署的id
     * @throws IOException
     */
    private void buildAndStartJar(List<String> mavens, List<Deploy> list, String[] split) throws IOException {
        CountDownLatch mainLatch = new CountDownLatch(mavens.size());
        FileUtils.writeFileInRealTime(StringUtils.format("{} 开始进行maven编译项目，编译详情可点击表格日志。。。。。。", DateUtil.now()));
        reloadHtml();
        mavens.forEach(maven -> threadPoolTaskExecutor.execute(() -> {
            try {
                List<Deploy> sameMavenList = list.stream().filter(deploy -> maven.equals(deploy.getMaven())).collect(Collectors.toList());
                //构建
                mavenBuild(maven, sameMavenList, split);
            } catch (IOException e) {
                log.error("构建失败,请重新检查代码{}", e.getMessage());
            } finally {
                mainLatch.countDown();
            }
        }));
        try {
            mainLatch.await();
            //查询编译情况
            QueryWrapper<Deploy> wrapper = new QueryWrapper<>();
            wrapper.in("id", split).eq("last_status", LastStatusEnum.BUILD_FAILED.getCode());
            List<Deploy> faildList = deployMapper.selectList(wrapper);
            if (CollectionUtil.isNotEmpty(faildList)) {
                String collect = faildList.stream().map(Deploy::getModuleName).collect(Collectors.joining());
                String info = StringUtils.format("{} ERROR 全部部署完毕，项目{}部署出现异常！！", DateUtil.now(), collect);
                FileUtils.writeFileInRealTime(info);
                List<Deploy> allList = getByIdList(split);
                FileUtils.writeAllLog(allList, info);
                alertFailMsg("部署完毕,有项目异常");
                log.info("全部部署完毕,项目{}部署异常", collect);
            }
        } catch (InterruptedException e) {
            log.error("构建失败{}", e.getMessage());
        }

    }

    private List<Deploy> getByIdList(String[] split) {
        QueryWrapper<Deploy> wrapper = new QueryWrapper<>();
        wrapper.in("id", split);
        return deployMapper.selectList(wrapper);
    }

    /**
     * 执行maven构建命令同时打印屏幕信息
     *
     * @param maven 编译命令
     * @param list  相同编译命令的数据
     * @param split 所有要部署的id
     * @return
     * @throws IOException
     */
    public Boolean mavenBuild(String maven, List<Deploy> list, String[] split) throws IOException {
        long start = System.currentTimeMillis();
        //重新生成日志
        FileUtils.recreateFileByPath(list);
        FileUtils.writeAllLog(list, StringUtils.format("{} 开始maven构建jar包中,请稍等片刻", DateUtil.now()));
        list.forEach(deploy -> {
            deploy.setLastStatus(LastStatusEnum.BUILDING.getCode());
            deploy.setLastDeployDate(new Date());
        });
        this.updateBatchById(list);
        reloadHtml();
        Process p;
        p = Runtime.getRuntime().exec(maven);
        InputStream is = p.getInputStream();
        String s;
        LineNumberReader lnr = new LineNumberReader(new InputStreamReader(is, "gbk"));
        Boolean flag = false;
        while ((s = lnr.readLine()) != null) {
            FileUtils.writeAllLog(list, s);
            if (s.contains("BUILD") && s.contains("SUCCESS")) {
                flag = true;
            }
            if (s.contains("FAILURE")) {
                flag = false;
                alertFailMsg("当前状态：构建失败");
                for (Deploy deploy : list) {
                    String info = StringUtils.format("{} ERROR 项目:{},maven构建失败,构建命令{},耗时：{}秒", DateUtil.now(), deploy.getModuleName(), maven, (System.currentTimeMillis() - start) / 1000);
                    FileUtils.writeFileByPath(deploy, info);
                    FileUtils.writeFileInRealTime(info);
                    log.info(info);
                }
                break;
            }
            if (((System.currentTimeMillis() - start) / (1000 * 60) > dssProperties.getBuildOutOfTime())) {
                flag = false;
                alertFailMsg("当前状态：构建超时");
                for (Deploy deploy : list) {
                    String info = StringUtils.format("{} ERROR 项目:{},maven构建已超过{}分钟,构建命令{},耗时：{}秒", DateUtil.now(), deploy.getModuleName(),
                            (System.currentTimeMillis() - start) / (1000 * 60), maven, (System.currentTimeMillis() - start) / 1000);
                    FileUtils.writeFileByPath(deploy, info);
                    FileUtils.writeFileInRealTime(info);
                    log.info(info);
                }
                break;
            }
            if (s.contains("Final") && s.contains("Memory")) {
                reloadHtml();
                break;
            }
        }
        if (flag) {
            for (Deploy deploy : list) {
                deploy.setLastStatus(LastStatusEnum.BUILD_SUCCESS.getCode());
                deploy.setLastDeployDate(new Date());
                deployMapper.updateById(deploy);
                reloadHtml();
                QueryWrapper<Deploy> wrapper = new QueryWrapper<>();
                wrapper.in("id", split);
                wrapper.and(queryWrapper ->
                        queryWrapper.eq("last_status", LastStatusEnum.BUILD_SUCCESS.getCode())
                                .or().eq("last_status", LastStatusEnum.START_SUCCESS.getCode())
                                .or().eq("last_status", LastStatusEnum.UPLOAD.getCode())
                );

                List<Deploy> deployList = deployMapper.selectList(wrapper);
                Integer count = deployList.size();

                String info = StringUtils.format("{} 项目:{},maven构建完毕,当前构建进度{}/{},耗时：{}秒", DateUtil.now(), deploy.getModuleName(), count, split.length, (System.currentTimeMillis() - start) / 1000);
                FileUtils.writeFileByPath(deploy, info);
                FileUtils.writeFileInRealTime(info);
                if (count.equals(split.length)) {
                    String infoAllSuccess = StringUtils.format("{} INFO 全部编译完成", DateUtil.now());
                    FileUtils.writeFileByPath(deploy, infoAllSuccess);
                    FileUtils.writeFileInRealTime(infoAllSuccess);
                    log.info(info);
                }
                log.info(info);
                //上传部署
                publisher.publishEvent(new UploadAndStartEvent(deploy, split));
            }
        } else {
            list.forEach(deploy -> {
                deploy.setLastStatus(LastStatusEnum.BUILD_FAILED.getCode());
                deploy.setLastDeployDate(new Date());
            });
            this.updateBatchById(list);
        }
        return flag;
    }


    /**
     * 自动批量部署代码
     * 后端
     *
     * @param ids
     * @return
     */
    @Override
    public Boolean deploySelect(String ids) throws Exception {
        //重新创建日志文件
        init();
        String[] split = ids.split(",");
        //不需要构建的，直接上传部署
        QueryWrapper<Deploy> wrapperNotBuild = new QueryWrapper<>();
        wrapperNotBuild.in("id", split).eq("build", BooleanTypeEnum.NO.getCode());
        List<Deploy> notBuildList = deployMapper.selectList(wrapperNotBuild);
        for (Deploy deploy : notBuildList) {
            publisher.publishEvent(new UploadAndStartEvent(deploy, split));
        }
        // 需要先构建的，先进行构建再上传部署
        QueryWrapper<Deploy> wrapper = new QueryWrapper<>();
        wrapper.in("id", split).eq("build", BooleanTypeEnum.YES.getCode());
        List<Deploy> list = deployMapper.selectList(wrapper);
        if (CollectionUtil.isEmpty(list)) {
            return true;
        }
        List<String> mavens = list.stream().map(Deploy::getMaven).distinct().collect(Collectors.toList());
        //编译构建,构建成功的直接丢事件进行部署
        buildAndStartJar(mavens, list, split);
        return true;
    }


    @Override
    public Boolean restartService(String ids) throws Exception {
        init();
        threadPoolTaskExecutor.execute(() -> {
            String[] split = ids.split(",");
            CountDownLatch mainLatch = new CountDownLatch(split.length);
            for (String s : split) {
                Long id = Long.valueOf(s);
                Deploy deploy = deployMapper.selectById(id);
                //开启多线程同时执行部署代码
                //通过线程池执行
                threadPoolTaskExecutor.execute(() -> {
                    try {
                        restartService(deploy);
                    } catch (Exception e) {
                        log.error(e.getMessage());
                    } finally {
                        mainLatch.countDown();
                    }
                });
                //更新最新部署时间
                deploy.setLastDeployDate(new Date());
                deployMapper.updateById(deploy);
            }
            try {
                mainLatch.await();
                log.info("全部批量部署完毕！！");
                FileUtils.writeFileInRealTime(StringUtils.format("全部批量部署完毕！！====="));
            } catch (InterruptedException | IOException e) {
                e.printStackTrace();
            }
        });
        return true;
    }

    /**
     * 重启服务
     *
     * @param deploy
     * @return
     */
    public void restartService(Deploy deploy) {
        Server server = serverService.getServerById(deploy.getServerId());
        long start = System.currentTimeMillis();
        Session session = null;
        try {
            session = remoteSshUtil.connect(server);
            //kill进程
            remoteSshUtil.exec(deploy.getCommandKill(), session);
            remoteSshUtil.exec(deploy.getCommandStart(), session);
            while (true) {
                try {
                    Thread.sleep(2000);
                    String s = remoteSshUtil.exec(deploy.getCommandLineCount(), session);
                    if ("1\n".equals(s)) {
                        FileUtils.writeFileInRealTime(StringUtils.format("{} IP:{} 项目：{}完成启动,部署耗时：{}秒", DateUtil.now(), server.getIp(), deploy.getModuleName(), (System.currentTimeMillis() - start) / 1000));
                        break;
                    }
                } catch (Exception e) {
                    log.error("服务出错:{}", e.getMessage());
                }
            }
        } catch (Exception e) {
            log.error(e.getMessage());
        }finally {
            remoteSshUtil.close(session);
        }
    }

    /**
     * 自动批量部署代码
     * 前端
     *
     * @return
     */
    @Override
    public Boolean javaScriptDeployBatch(List<Long> split) {
        CountDownLatch mainLatch = new CountDownLatch(split.size());
        split.stream().map(deployMapper::selectById).forEach(deploy -> {
            threadPoolTaskExecutor.execute(() -> {
                try {
                    allDeployJavaScript(deploy);
                } catch (Exception e) {
                    log.error(e.getMessage());
                    throw new ServiceException(e.getMessage());
                }
                mainLatch.countDown();
            });
            deploy.setLastDeployDate(new Date());
            deployMapper.updateById(deploy);
            log.info("前端部署完毕：{}", deploy.getModuleName());
        });
        try {
            mainLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return true;
    }

    @Override
    public void jobToDeployHtml(Long projectId, Long namespaceId) {
        AdmNamespace admNamespace = admNamespaceMapper.selectById(namespaceId);
        AdmProject admProject = admProjectMapper.selectById(projectId);
        LambdaQueryWrapper<Deploy> query = Wrappers.lambdaQuery(Deploy.class);
        query.eq(Deploy::getProjectId, projectId).eq(Deploy::getNamespaceId, namespaceId);
        List<Deploy> list = this.list(query);
        List<Long> collect = list.stream().map(Deploy::getId).collect(Collectors.toList());
        System.out.println(StringUtils.format("前端开始更新,项目ID:{},项目名称:{},命名空间:{},部署id：{}", projectId, admProject.getProjectName(), admNamespace.getName(), JacksonUtils.toString(collect)));
        javaScriptDeployBatch(collect);
    }

    /**
     * 部署前端
     *
     * @param deploy
     * @return
     */
    public void allDeployJavaScript(Deploy deploy) {
        Server server = serverService.getServerById(deploy.getServerId());
        long start = System.currentTimeMillis();
        Session session = null;
        try {
             session = remoteSshUtil.connect(server);
            long start1 = System.currentTimeMillis();
            log.info("-----开始上传{}代码包到{}----", deploy.getModuleName(), server.getIp());
            remoteSshUtil.putFile(session, deploy.getLocalFile(), deploy.getRemoteTargetDirectory());
            log.info("-----上传{}到服务器{}成功,耗时{}秒----", deploy.getModuleName(), server.getIp(), (System.currentTimeMillis() - start1) / 1000);
            remoteSshUtil.exec(deploy.getCommandStart(), session);
            log.info("{}部署耗时：{}秒", deploy.getModuleName(), (System.currentTimeMillis() - start) / 1000);
        } catch (Exception e) {
            log.error(e.getMessage());
            throw new ServiceException(e.getMessage());
        }finally {
            remoteSshUtil.close(session);
        }
    }

    @Override
    public Boolean stopService(String ids) throws IOException {
        init();
        threadPoolTaskExecutor.execute(() -> {
            String[] split = ids.split(",");
            CountDownLatch mainLatch = new CountDownLatch(split.length);
            for (String s : split) {
                Long id = Long.valueOf(s);
                Deploy deploy = deployMapper.selectById(id);
                //开启多线程同时执行部署代码
                //通过线程池执行
                threadPoolTaskExecutor.execute(() -> {
                    try {
                        stopService(deploy);
                    } catch (Exception e) {
                        log.error(e.getMessage());
                    } finally {
                        mainLatch.countDown();
                    }
                });
                //更新最新部署时间
                deploy.setLastDeployDate(new Date());
                deployMapper.updateById(deploy);
            }
            try {
                mainLatch.await();
                log.info("服务已全部停止！！");
                FileUtils.writeFileInRealTime(String.format("服务已全部停止！！====="));
            } catch (InterruptedException | IOException e) {
                e.printStackTrace();
            }
        });
        return true;
    }

    public Boolean stopService(Deploy deploy) {
        Server server = serverService.getServerById(deploy.getServerId());
        Session session =null;
        try {
            session = remoteSshUtil.connect(server);
            //kill进程
            remoteSshUtil.exec(deploy.getCommandKill(), session);
            return true;
        } catch (Exception e) {
            log.error(e.getMessage());
        }finally {
            remoteSshUtil.close(session);
        }
        return false;
    }

    /**
     * 查询当前部署成功的数据
     *
     * @return
     */
    @Override
    public List<DeployVo> getSuccess() {
        List<Deploy> list = deployMapper.selectList(Wrappers.lambdaQuery(Deploy.class).eq(Deploy::getLastStatus, LastStatusEnum.START_SUCCESS.getCode())
                .orderByDesc(Deploy::getLastDeployDate));
        return convertToVo(list);
    }

    @Override
    public void init() throws IOException {
        //文件清空
        remoteSshUtil.recreateFile();
        List<Deploy> list = list(Wrappers.query());
        list.forEach(deploy -> {
            deploy.setLastStatus(LastStatusEnum.INIT.getCode());
            deploy.setSpeed("");
            deploy.setTransfered("");
            deploy.setSpeedOfProgress("");
            deploy.setFileSize("");
        });
        if (CollectionUtil.isNotEmpty(list)) {
            updateBatchById(list);
        }
    }


    /**
     * 打包上传启动功能
     */
    @Override
    public void startService(Deploy deploy, String[] split) throws IOException {
        long start = System.currentTimeMillis();
        try {
            Server server = serverService.getServerById(deploy.getServerId());
            Session session = remoteSshUtil.connect(server);
            String startUploadInfo = StringUtils.format("{} 开始上传项目：{}到服务器ip：{}", DateUtil.now(), deploy.getModuleName(), server.getIp());
            FileUtils.writeFileInRealTime(startUploadInfo);
            FileUtils.writeFileByPath(deploy, startUploadInfo);
            deploy.setLastStatus(LastStatusEnum.UPLOAD.getCode());
            deployMapper.updateById(deploy);
            reloadHtml();
            //sftp上传文件
            remoteSshUtil.putJarFile(session, deploy);

            String uploadSuccessInfo = StringUtils.format("{} 上传项目：{}到服务器ip：{}成功,上传耗时：{}秒", DateUtil.now(), deploy.getModuleName(), server.getIp(), (System.currentTimeMillis() - start) / 1000);
            FileUtils.writeFileInRealTime(uploadSuccessInfo);
            FileUtils.writeFileByPath(deploy, uploadSuccessInfo);
            reloadHtml();
            //文件夹授权
            remoteSshUtil.exec("sudo chmod 777 -R " + deploy.getRemoteTargetDirectory(), session);
            //kill进程
            remoteSshUtil.exec(deploy.getCommandKill(), session);
            remoteSshUtil.exec(deploy.getCommandStart(), session);
            //防止因为异步操作进度未来得及更新获取的不是最新的，等2秒重新查询结果
            Thread.sleep(2000);
            deploy = deployMapper.selectById(deploy.getId());
            long temp = System.currentTimeMillis();
            while (true) {
                try {
                    Thread.sleep(2000);
                    String s = remoteSshUtil.exec(deploy.getCommandLineCount(), session);
                    if ("1\n".equals(s)) {
                        deploy.setLastStatus(LastStatusEnum.START_SUCCESS.getCode());
                        deployMapper.updateById(deploy);
                        QueryWrapper<Deploy> wrapper = new QueryWrapper<>();
                        wrapper.in("id", split).eq("last_status", LastStatusEnum.START_SUCCESS.getCode());
                        Integer integer = deployMapper.selectCount(wrapper);
                        String info3 = StringUtils.format("{} ip：{} 项目：{}完成启动,当前启动进度{}/{},部署耗时：{}秒", DateUtil.now(), server.getIp(), deploy.getModuleName(), integer, split.length, (System.currentTimeMillis() - start) / 1000);
                        FileUtils.writeFileInRealTime(info3);
                        FileUtils.writeFileByPath(deploy, info3);
                        reloadHtml();
                        if (integer.equals(split.length)) {
                            QueryWrapper<Deploy> queryWrapper = new QueryWrapper<>();
                            queryWrapper.in("id", split);
                            List<Deploy> deployList = deployMapper.selectList(queryWrapper);
                            String info = StringUtils.format("{} INFO 全部成功部署完毕！！", DateUtil.now());
                            FileUtils.writeFileInRealTime(info);
                            FileUtils.writeAllLog(deployList, info);
                            alertSuccessMsg("全部成功部署完毕");
                            log.info(info);
                        }
                        break;
                    }
                    //超时
                    if ((System.currentTimeMillis() - temp) / 1000 > dssProperties.getStartOutOfTime()) {
                        deploy.setLastStatus(LastStatusEnum.START_FAILED.getCode());
                        deployMapper.updateById(deploy);
                        String info4 = StringUtils.format("{} ERROR服务器{} {}已耗时：{}秒,可能启动失败，请检查服务器日志", DateUtil.now(), server.getIp(), deploy.getModuleName(), (System.currentTimeMillis() - start) / 1000);
                        FileUtils.writeFileInRealTime(info4);
                        FileUtils.writeFileByPath(deploy, info4);
                        alertFailMsg(StringUtils.format("{}启动失败", deploy.getModuleName()));
                        break;
                    }
                } catch (Exception e) {
                    log.error("服务出错:{}", e.getMessage());
                    deployError(deploy, e.getMessage());
                }
            }
            remoteSshUtil.close(session);
        } catch (Exception e) {
            log.error(e.getMessage());
            deployError(deploy, e.getMessage());
        }
    }

    /**
     * 部署失败
     *
     * @param deploy
     * @param message
     * @throws IOException
     */
    private void deployError(Deploy deploy, String message) throws IOException {
        Server server = serverService.getServerById(deploy.getServerId());
        deploy.setLastStatus(LastStatusEnum.START_FAILED.getCode());
        deployMapper.updateById(deploy);
        String info4 = StringUtils.format("{} ERROR服务器{} {},部署失败，原因：{}", DateUtil.now(), server.getIp(), deploy.getModuleName(), message);
        FileUtils.writeFileInRealTime(info4);
        FileUtils.writeFileByPath(deploy, info4);
        alertFailMsg(StringUtils.format("{}启动失败", deploy.getModuleName()));
    }

    /**
     * 弹窗提示
     *
     * @param data
     */
    private void alertSuccessMsg(String data) {
        websocketEndPoint.send(WsSendDto.builder().type(2).table("deploy").data(data).build());
    }

    /**
     * 弹窗提示
     *
     * @param data
     */
    private void alertFailMsg(String data) {
        websocketEndPoint.send(WsSendDto.builder().type(3).table("deploy").data(data).build());
    }

    /**
     * 仅刷新表格
     */
    private void reloadHtml() {
        websocketEndPoint.send(WsSendDto.builder().type(1).table("deploy").build());
    }
}
